#include<stdio.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
#include<stdlib.h>

typedef void (*func)();
#define Num 5

func F[Num];

void Download(){
  printf("This is Download\n");
}
void Upload(){
  printf("This is Upload\n");
}
void Flush(){
  printf("This is Flush\n");
}
void Sleep(){
  printf("This is Sleep\n");
}

void initF(func f[], func pf){
  int i = 0;
  for(i = 0 ; i < Num; ++i){
    if(f[i] == NULL) break;
  }
  if(i == Num) f[i] = NULL;
  else{
    f[i] = pf;
    f[i + 1] = NULL;
  }
}

int main(){
  initF(F, Download);
  initF(F, Upload);
  initF(F, Flush);
  initF(F, Sleep);

  int id = fork();
  if(id < 0){
    perror("fork");
    return 1;
  }
  else if(id == 0){
    int cnt = 5;
    while(cnt--){
      printf("子进程， pid：%d\n", getpid());
      sleep(1);
    }
  }
  else{
    printf("父进程非阻塞等待子进程\n");
    int status;
    while(1){
      int rid = waitpid(id, &status, WNOHANG);
      if(rid == -1){
        printf("子进程回收失败\n");
        printf("signal: %d, %d\n", status & 0x7F, WTERMSIG(status));
				break;
      }
			else if(rid == 0){
				for(int i = 0; i < Num - 1; ++i){
					F[i]();
				}
				printf("本轮等待子进程失败，需进行下一次等待\n");
        sleep(1);
	    }
			else{
				printf("等待子进程成功\n");
				printf("signal: %d, %d\n", status & 0x7F, WTERMSIG(status));
				printf("errcode: %d, %d\n", (status >> 8) & 0xFF, WEXITSTATUS(status));
        break;
			}
    }
  }
  return 0;
}






/*通过status来获取信息 waitpid方法*/
//int main(){
//  int id = fork();  
//  if(id < 0){
//    perror("fork");
//    return 1;
//  }
//  else if(id == 0){
//    //测试正常退出
//   // int cnt = 5;
//   // while(cnt--){
//   //   printf("子进程, pid:%d, ppid:%d\n",getpid(), getppid());
//   //   sleep(1);      
//   // }
//   // exit(5);
//
//    //不正常退出
//    int a = 0;
//    a /= 0;
//  }
//  else{
//    printf("父进程回收子进程\n");
//    int status = 0;
//    int rid = waitpid(id, &status, 0);
//    if(rid == id){
//      printf("子进程回收成功，子进程pid为%d\n", rid);
//      printf("signal: %d, %d\n", status & 0x7F, WTERMSIG(status));
//      printf("errcode: %d, %d\n", (status >> 8) & 0xFF, WEXITSTATUS(status));
//    }
//    else{
//      printf("子进程回收失败\n");
//      printf("signal: %d, %d\n", status & 0x7F, WTERMSIG(status)); 
//    }
//  }
//  return 0;
//}






/*使用waitpid等到某个进程*/
//int main(){
//  pid_t id = fork();
//  if(id < 0){
//    perror("fork");
//    return 1;
//  }
//  else if(id == 0){
//    int cnt = 5;
//    while(cnt--){
//      printf("子进程, pid:%d, ppid:%d\n",getpid(), getppid());
//      sleep(1);
//    }
//  }
//  else{
//    printf("父进程休眠10s\n");
//    sleep(10);
//    printf("父进程开始回收子进程\n");
//    int rid = waitpid(id, NULL, 0);
//    if(rid == id){
//      printf("回收子进程成功，子进程pid:%d\n", rid);
//    }
//    else{
//      printf("回收子进程失败\n");
//    }
//  }
//  return 0;
//}






/*验证wait是阻塞等待*/
//int main(){
//  pid_t id = fork();
//  if(id < 0){
//    perror("fork");
//    return 1;
//  }
//  else if(id == 0){
//    while(1){
//      printf("子进程, pid:%d, ppid:%d\n",getpid(), getppid());
//      sleep(1);
//    }
//  }
//  else{
//    printf("父进程：等待回收子进程\n");
//    pid_t rid = wait(NULL);
//    printf("回收完成，回收进程的pid是%d\n", rid);
//  }
//  return 0;
//}



/*让子进程处于僵尸状态后，父进程使用wait回收*/
//int main(){
//  pid_t id = fork();
//  if(id < 0){
//    perror("fork");
//    return 1;
//  }
//
//  else if(id == 0){
//   int cnt = 5;
//    while(cnt--){
//      printf("子进程：pid是%d, ppid是%d, \n", getpid(), getppid());
//      sleep(1);
//    }
//    //exit(10);
//  }
//
//  else{
//  //父进程等待子进程的结束
//    sleep(10);//让父进程先休眠10s，这样可以让子进程有5s时间处于僵尸状态
//    pid_t rid = wait(NULL);
//    printf("wait返回值: rid=%d, 子进程id=%d\n", rid, id);  // 添加调试输出
//    if(rid == id){
//      printf("等待子进程成功，子进程pid%d\n", id);
//    } 
//    else{
//      printf("等待子进程失败\n");
//    }
//    sleep(3);//再休眠3s，查看子进程和父进程状态
//  }
//  return 0;
//}
